#include "FeedManager.h"

#ifdef WIN32
const string FEED_FOLDER = "\\feeds\\";
#else
const string FEED_FOLDER = "feeds/";
#endif

FeedManager::FeedManager()
{
        currentId = 0;
};

FeedManager::~FeedManager()
{
        this->archivoDatosFeedFijo.cerrarArchivo();
        this->archivoFeedIndice.cerrarArchivo();
        this->archivoDatosFeedVariable.cerrarArchivo();
};

TCId FeedManager::generateFeedID()
{
        return ++currentId;
}

void FeedManager::ActualizarGeneradorId()
{
        //estoy parado al final del archivo indice,
        //me muevo un registro hacia atras.
        RegistroFijoFeedIndex registroIndice;
        RegistroVariableFeedData registroDatos;

        int posicion = this->archivoFeedIndice.getOffsetArchivo() -
                registroIndice.getTamanioRegistro();

        if (posicion >= 0)
        {
                if (this->archivoFeedIndice.posicionarEnArchivo(posicion))
                {
                        if (this->archivoFeedIndice.leerRegistro((Registro*)&registroIndice))
                        {
                                //tengo el offset del registro en el archivo data.
                                //traigo de ahi el ultimo id.
                                if (this->archivoDatosFeedFijo.posicionarEnArchivo(registroIndice.getOffsetRegistroEnArchivo()))
                                {
                                        registroDatos.setTamanioRegistro(registroIndice.getLongitudRegistroEnArchivo());

                                        if (this->archivoDatosFeedFijo.leerRegistro((Registro*)&registroDatos))
                                        {
                                                this->currentId = registroDatos.getIdFeed();
                                        }
                                }
                        }
                }
                //si no pudo posicionarse es porque estaba vacio, entonces
                //deja el id en 0.
        }
}

bool FeedManager::InicializarManager(string DirectorioInicial)
{
        bool crearArchivos = true;
        this->directorioInicial = DirectorioInicial;

        this->archivoDatosFeedFijo.setNombreArchivo(DirectorioInicial +
                FEED_FOLDER + "data.dat");
        this->archivoDatosFeedVariable.setNombreArchivo(DirectorioInicial +
                FEED_FOLDER + "datav.dat");
        this->archivoFeedIndice.setNombreArchivo(DirectorioInicial +
                FEED_FOLDER + "index.dat");

        //si falla el modo (rb+) los abro en modo (wb+)

        if (this->archivoDatosFeedFijo.abrirArchivo(maActualizacion))
        {
                if (this->archivoDatosFeedVariable.abrirArchivo(maActualizacion))
                {
                        if (this->archivoFeedIndice.abrirArchivo(maActualizacion))
                        {
                                crearArchivos = false;

                                //si levante de disco, tengo que actualizar el id
                                //con el ultimo grabado (no importa si esta dado de
                                //baja o no, tiene que ser el ultimo id generado).
                                ActualizarGeneradorId();                                
                        }
                        else
                        {
                                this->archivoDatosFeedFijo.cerrarArchivo();
                                this->archivoDatosFeedVariable.cerrarArchivo();
                        }
                }
                else
                {
                        this->archivoDatosFeedFijo.cerrarArchivo();
                }
        }

        //no pude abrir los 3 simultaneamente, asi que los creo (o trunco).
        if (crearArchivos)
        {
                if (this->archivoDatosFeedFijo.crearArchivo())
                {
                        if (this->archivoDatosFeedVariable.crearArchivo())
                        {
                                if (this->archivoFeedIndice.crearArchivo())
                                {
                                        return true;
                                }

                                this->archivoDatosFeedFijo.cerrarArchivo();
                                this->archivoDatosFeedVariable.cerrarArchivo();
                                return false;
                        }

                        this->archivoDatosFeedFijo.cerrarArchivo();
                        return false;
                }
                
                return false;
        }

        return true;
}

bool FeedManager::AgregarFeed(Feed &nuevoFeed, TCId &idFeed)
{
         //Primero me muevo al final:
         if ((this->archivoDatosFeedVariable.posicionarAlFinal()) &&
             (this->archivoFeedIndice.posicionarAlFinal()) &&
             (this->archivoDatosFeedFijo.posicionarAlFinal()))
         {
                //estoy al final de los 3. Empiezo por insertar los datos
                //y si pude, finalmente agrego en el indice.
                RegistroVariableFeedData registroData;
                RegistroFijoFeedIndex registroIndice;
                RegistroFijoFeedDataVariable registroDataVariable;

                idFeed = this->generateFeedID(); 
                registroData.setIdFeed(idFeed);
                registroData.setURL(nuevoFeed.getURL());
                registroDataVariable.setFechaUltimaActualizacion(nuevoFeed.getDate());

                if (this->archivoDatosFeedFijo.escribirRegistro((Registro*)&registroData) &&
                    this->archivoDatosFeedVariable.escribirRegistro((Registro*)&registroDataVariable))
                {                        
                        //si lo pudo agregar, lo agrega al indice
                        registroIndice.setLongitudRegistroEnArchivo(registroData.getTamanioRegistro());
                        registroIndice.setOffsetRegistroEnArchivo(this->archivoDatosFeedFijo.getLastRecordOffsetArchivo());

                        return (this->archivoFeedIndice.escribirRegistro((Registro*)&registroIndice));
                }
         }

         return false;
}

bool FeedManager::EliminarFeed(unsigned int posicionGlobal)
{
        //Primero me posiciono.
        RegistroFijoFeedIndex registroIndice;
        unsigned int posicion;

        posicion = registroIndice.getTamanioRegistro() * posicionGlobal;

        if (this->archivoFeedIndice.posicionarEnArchivo(posicion))
        {
                if (archivoFeedIndice.leerRegistro((Registro*)&registroIndice))
                {
                        registroIndice.setEstadoRegistro(false);

                        if (this->archivoFeedIndice.posicionarEnArchivo(posicion))
                        {
                                archivoFeedIndice.escribirRegistro((Registro*)&registroIndice);

                                return true;
                        }
                }
        }

        return false;
}

bool FeedManager::ActualizarFechaFeed(unsigned int posicionGlobal)
{
        RegistroFijoFeedDataVariable registroDataVariable;
        unsigned int posicion;

        posicion = posicionGlobal * registroDataVariable.getTamanioRegistro();

        if (this->archivoDatosFeedVariable.posicionarEnArchivo(posicion))
        {
                registroDataVariable.setFechaUltimaActualizacion(time(NULL));

                archivoDatosFeedVariable.escribirRegistro((Registro*)&registroDataVariable);
        }

        return false;
}

ListaConsultaFeed FeedManager::ConsultarFeed()
{
        ListaConsultaFeed resultado;
        FeedItemConsulta* itemFeedConsulta;

        RegistroFijoFeedIndex registroIndice;
        RegistroVariableFeedData registroData;
        RegistroFijoFeedDataVariable registroDataVariable;

        this->archivoFeedIndice.posicionarEnArchivo(0); //voy al ppio.
        //this->archivoDatosFeedVariable.posicionarEnArchivo(0); //voy al ppio.
        int posicionGlobal = 0;

        while (!this->archivoFeedIndice.getEsFinDeArchivo())
        {
                if (this->archivoFeedIndice.leerRegistro((Registro*)&registroIndice))
                {
                        if (registroIndice.getEstadoRegistro())
                        {
                                if (this->archivoDatosFeedFijo.posicionarEnArchivo(registroIndice.getOffsetRegistroEnArchivo()))
                                {
                                        registroData.setTamanioRegistro(registroIndice.getLongitudRegistroEnArchivo());
                                        if (this->archivoDatosFeedFijo.leerRegistro((Registro*)&registroData))
                                        {
                                                if (archivoDatosFeedVariable.posicionarEnArchivo(posicionGlobal * registroDataVariable.getTamanioRegistro()))
                                                {
                                                        if (archivoDatosFeedVariable.leerRegistro((Registro*)&registroDataVariable))
                                                        {
                                                                itemFeedConsulta = new FeedItemConsulta();

        	        					itemFeedConsulta->setId(registroData.getIdFeed());
                                                                itemFeedConsulta->setURL(registroData.getURL());
                                                                itemFeedConsulta->setPosicionGlobal(posicionGlobal);
                                                                itemFeedConsulta->setDate(registroDataVariable.getFechaUltimaActualizacion());
                                                                resultado.push_back(*itemFeedConsulta);
                                                                
                                                                delete itemFeedConsulta;
                                                        }
                                                }
                                        }
                                }
                        }

                        posicionGlobal++;
                }
        }

        return resultado;
}

//Deja solo los feeds que tienen el bit de estado en true.
void FeedManager::ReorganizarArchivos()
{
        bool archivoCreado;

        RegistroFijoFeedIndex registroIndice;
        RegistroVariableFeedData registroData;
        RegistroFijoFeedDataVariable registroDataVariable;

        Archivo archivoIndiceReorganizado;
        Archivo archivoDataReorganizado;
        Archivo archivoDataVariableReorganizado;

        string sNombreArchivoIndice = directorioInicial + FEED_FOLDER + "index.dat";
        string sNombreArchivoData = directorioInicial + FEED_FOLDER + "data.dat";
        string sNombreArchivoDataVariable = directorioInicial + FEED_FOLDER + "datav.dat";
        string sNombreArchivoIndiceTemp = directorioInicial + FEED_FOLDER + "index.dat.Temp";
        string sNombreArchivoDataTemp = directorioInicial + FEED_FOLDER + "data.dat.Temp";
        string sNombreArchivoDataVariableTemp = directorioInicial + FEED_FOLDER + "datav.dat.Temp";

        archivoDataReorganizado.setNombreArchivo(sNombreArchivoDataTemp);
        archivoDataVariableReorganizado.setNombreArchivo(sNombreArchivoDataVariableTemp);
        archivoIndiceReorganizado.setNombreArchivo(sNombreArchivoIndiceTemp);

        if (archivoDataReorganizado.crearArchivo() &&
            archivoDataVariableReorganizado.crearArchivo() &&
            archivoIndiceReorganizado.crearArchivo())
        {
                //voy al inicio.
                this->archivoFeedIndice.posicionarEnArchivo(0);
                int posicionGlobal = 0;

                //los archivos a reorganizar estan abiertos!!
                while (!this->archivoFeedIndice.getEsFinDeArchivo())
                {
                        if (this->archivoFeedIndice.leerRegistro((Registro*)&registroIndice))
                        {
                                if (registroIndice.getEstadoRegistro())
                                {
                                        if (this->archivoDatosFeedFijo.posicionarEnArchivo(registroIndice.getOffsetRegistroEnArchivo()) &&
                                            this->archivoDatosFeedVariable.posicionarEnArchivo(posicionGlobal * registroDataVariable.getTamanioRegistro()))
                                        {
                                                registroData.setTamanioRegistro(registroIndice.getLongitudRegistroEnArchivo());

                                                if (this->archivoDatosFeedFijo.leerRegistro((Registro*)&registroData) &&
                                                    this->archivoDatosFeedVariable.leerRegistro((Registro*)&registroDataVariable))
                                                {
                                                        //ya lei todo, grabo sobre los reorganizados
                                                        archivoDataReorganizado.escribirRegistro((Registro*)&registroData);
                                                        archivoDataVariableReorganizado.escribirRegistro((Registro*)&registroDataVariable);

                                                        registroIndice.setEstadoRegistro(true);
                                                        registroIndice.setLongitudRegistroEnArchivo(registroData.getTamanioRegistro());
                                                        registroIndice.setOffsetRegistroEnArchivo(archivoDataReorganizado.getLastRecordOffsetArchivo());

                                                        archivoIndiceReorganizado.escribirRegistro((Registro*)&registroIndice);
                                                }
                                        }

                                }
                                posicionGlobal++;
                        }
                }

                //liquido los anteriores
                this->archivoDatosFeedFijo.cerrarArchivo();
                this->archivoDatosFeedVariable.cerrarArchivo();
                this->archivoFeedIndice.cerrarArchivo();

                archivoIndiceReorganizado.cerrarArchivo();
                archivoDataReorganizado.cerrarArchivo();
                archivoDataVariableReorganizado.cerrarArchivo();

                Archivo::EliminarArchivo(sNombreArchivoIndice.c_str());
                Archivo::EliminarArchivo(sNombreArchivoData.c_str());
                Archivo::EliminarArchivo(sNombreArchivoDataVariable.c_str());

                Archivo::RenombrarArchivo(sNombreArchivoIndiceTemp.c_str(), sNombreArchivoIndice.c_str());
                Archivo::RenombrarArchivo(sNombreArchivoDataTemp.c_str(), sNombreArchivoData.c_str());
                Archivo::RenombrarArchivo(sNombreArchivoDataVariableTemp.c_str(), sNombreArchivoDataVariable.c_str());

                this->InicializarManager(this->directorioInicial);
        }
}

//IMPLEMENTACION CLASE FEEDITEMCONSULTA
FeedItemConsulta::~FeedItemConsulta()
{
}

FeedItemConsulta::FeedItemConsulta()
{
        this->posicionGlobal = 0;
        this->URL = "";
}

TCId FeedItemConsulta::getId()
{
	return this->id;
}

string FeedItemConsulta::getURL()
{
        return this->URL;
}

int FeedItemConsulta::getPosicionGlobal()
{
        return this->posicionGlobal;
}

TCTimeStamp FeedItemConsulta::getDate()
{
	return this->date;
}

void FeedItemConsulta::setId(TCId id)
{
	this->id = id;
}

void FeedItemConsulta::setURL(string URL)
{
        this->URL = URL;
}

void FeedItemConsulta::setPosicionGlobal(int posicionGlobal)
{
        this->posicionGlobal = posicionGlobal;
}

void FeedItemConsulta::setDate(TCTimeStamp value)
{
        this->date = value;
}


